﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.Serialization;
using System.Windows.Media;
using System.Linq;
using System.Windows.Media.Media3D;

namespace GameBoard
{
    [DataContract(Namespace = "")]
    public class MoveablePicture : INotifyPropertyChanged
    {
        private PictureVisualFactory _charImageFactory;

        public PictureVisualFactory TheCharImageFactory
        {
            get { return _charImageFactory; }
            set { _charImageFactory = value; }
        }

        private ConeVisualFactory _baseCone;

        public ConeVisualFactory TheBaseConeFactory
        {
            get { return _baseCone; }
            set { _baseCone = value; }
        }

        private List<int> _movementCirclesRadiusList;

        [DataMember]
        public List<int> MovementCirclesRadiusList
        {
            get { return _movementCirclesRadiusList; }
            set { _movementCirclesRadiusList = value; }
        }

        internal List<MovementCircleVisualFactory> _movementCirclesFactories = new List<MovementCircleVisualFactory>();

        internal List<MovementCircleVisualFactory> MovementCirclesFactories
        {
            get { return _movementCirclesFactories; }
            set { _movementCirclesFactories = value; }
        }

        public List<Guid> ActivateableIDs
        {
            get
            {
                var foundItems = new List<Guid>();
                foundItems.Add(TheBaseConeFactory.FactoryVisualID);
                return foundItems;
            }
        }

        public String AdditionalDisplayText { get; set; }

        public InfoTextVisualFactory TheInfoTextFactory { get; set; }

        private double _pictureOffset;

        private String _name;

        [DataMember]
        public String Name
        {
            get { return _name; }
            set { _name = value; }
        }

        [DataMember]
        public double Speed { get; set; }

        [DataMember]
        public Color PieceColor { get; set; }

        [DataMember]
        public Guid UniqueID { get; set; }

        [DataMember]
        public double LongestPictureSide { get; set; }

        [DataMember] private Point3D _location;

        public Point3D Location
        {
            get { return _location; }
            private set
            {
                _location = value;
                SetLocationTo(value);
            }
        }

        public double BaseConeRadius { get; set; }

        private bool _isSelected;

        public bool IsSelected
        {
            get { return _isSelected; }
            set
            {
                _isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }

        private double _flightHeight = 0;
        public double FlightHeight 
        {
            get
            {
                return _flightHeight;
            }
            set
            {
                _flightHeight = value;
                OnPropertyChanged("FlightHeight");
            }
        }


        private string _pictureFileName = "";

        [DataMember]
        public String PictureFileName
        {
            get { return _pictureFileName; }
            set { _pictureFileName = value; }
        }

        public String PictureFileAbsolutePath
        {
            get { return Directory.GetCurrentDirectory() + "\\" + _pictureFileName; }
        }

        private List<StatusEffectDisplay> _statusEffects = new List<StatusEffectDisplay>();

        [DataMember]
        public List<StatusEffectDisplay> StatusEffects
        {
            get { return _statusEffects; }
            set { _statusEffects = value; }
        }

        public MoveablePicture(String pictureFile,
            double longestEdge, String imageName,
            Color pieceColor,
            Point3D location,
            List<StatusEffectDisplay> statuses,
            double speed,
            List<int> movementCircleRadiusList,
            Guid uniqueID
            )
        {
            MovementCirclesRadiusList = movementCircleRadiusList;
            PieceColor = pieceColor;
            Name = imageName;
            Speed = speed;
            _location = location;
            PictureFileName = pictureFile;
            LongestPictureSide = longestEdge;
            _charImageFactory = ImageToRectangle(pictureFile, longestEdge, location, movementCircleRadiusList);
            RemakeInfoText(statuses);
            StatusEffects = statuses;
            UniqueID = uniqueID;
        }

        [OnDeserialized]
        public void OnDeserialized(StreamingContext context)
        {
            _movementCirclesFactories = new List<MovementCircleVisualFactory>();
            _charImageFactory = ImageToRectangle(PictureFileName, LongestPictureSide, _location,
                MovementCirclesRadiusList);
            RemakeInfoText(StatusEffects);
        }

        public void RemakeInfoText(List<StatusEffectDisplay> statuses)
        {
            if (TheInfoTextFactory!=null)
            {
                //The status-effects should be removed when changed, otherwise
                //they linger forever and ever.
                VisualsViewModel.Instance.RemoveVisuals(TheInfoTextFactory.FactoryVisualID);
            }
            String status = Name;
            foreach (var cur in statuses)
            {
                status = status + "\n   " + cur.Description + " -- R:" + cur.TurnsRemaining;
                if (!String.IsNullOrWhiteSpace(cur.ModifierDescription))
                {
                    status = status + " M:" + cur.ModifierDescription;
                }
            }
            var infoData = new InfoTextVisualData
            {
                Position = Location,
                FontSize = 18,
                Background = new SolidColorBrush(Colors.Wheat),
                Foreground = Brushes.Black,
                Text = status,
                LongestPictureSide = LongestPictureSide,
                HeightChange = 3,
                BelongsToMoveablePicture = true,
            };
            TheInfoTextFactory = new InfoTextVisualFactory(infoData);
        }




        internal const double ConeHeight = 2.5;
        private PictureVisualFactory ImageToRectangle(String imageFile, double longestEdge, Point3D location,
            List<int> movementCircleRadiusList)
        {
            ImageBrush frontBrush = MaterialMaker.MakeImageMaterial(imageFile);
            Material frontMaterial = new DiffuseMaterial(frontBrush);

            //The base cone should be larger than the smallest side.
            var pictureDimensions = GetProportionedPieceSizes(frontBrush, longestEdge);
            var width = pictureDimensions.Item1;
            var length = pictureDimensions.Item2;
            
            var pictureData = new PictureVisualData
            {
                MaterialFile = imageFile,
                Length = length,
                Width = width,
                Origin = location,
                Normal = new Vector3D(0.00001, 0.00001, 1),
                LengthDirection = new Vector3D(0, -.5, .5),
                BelongsToMoveablePicture = true,
            };

            var charPic = new PictureVisualFactory(pictureData);


            BaseConeRadius = longestEdge/3;
            var baseConeData = new ConeVisualData
            {
                Height = ConeHeight,
                BaseRadius = BaseConeRadius,
                TopRadius = BaseConeRadius,
                MaterialColor = PieceColor,
                Normal = new Vector3D(0,0,1),
                Origin = new Point3D(location.X, location.Y, 0),
                IsNotSolid=true,
                BelongsToMoveablePicture = true,
            };
            TheBaseConeFactory = new ConeVisualFactory(baseConeData);

            for (int curIndex = 0; curIndex < movementCircleRadiusList.Count; curIndex++)
            {
                var curCircleSize = movementCircleRadiusList[curIndex];
                var circleData = new MovementCircleVisualData
                {
                    Speed = Speed,
                    CurCircleSize = curCircleSize,
                    Location = location,
                    MaterialColor = PieceColor,
                };
                var curFact = new MovementCircleVisualFactory(circleData);
                MovementCirclesFactories.Add(curFact);
            }
            return charPic;
        }

        //Returns width and length
        private Tuple<double, double> GetProportionedPieceSizes(ImageBrush frontBrush, double longestEdge)
        {
            double length, width;
            double origWidth = frontBrush.ImageSource.Width;
            double origLength = frontBrush.ImageSource.Height;
            if (origWidth > origLength)
            {
                width = longestEdge;
                length = longestEdge/(origWidth/origLength);
            }
            else
            {
                width = (origWidth/origLength)*longestEdge;
                length = longestEdge;
            }
            return new Tuple<double, double>(width, length);
        }


        internal void SetLocationTo(Point3D point3D)
        {
            double originalZ = Math.Round(point3D.Z, 4);
            _location = point3D;
            TheInfoTextFactory.SetLocation(point3D);
            TheBaseConeFactory.SetLocation(point3D);
            TheCharImageFactory.SetLocation(point3D);
            foreach (var cur in MovementCirclesFactories)
            {
                cur.SetLocation(point3D);
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        #endregion



        [DataMember]
        private HashSet<BoardsViewModel.BoardTypes> _boardsInvisibleTo = new HashSet<BoardsViewModel.BoardTypes>();
        public HashSet<BoardsViewModel.BoardTypes> BoardsInvisibleTo
        {
            get { return _boardsInvisibleTo; }
            set { _boardsInvisibleTo = value; }
        }




        internal void MarkNotInvisibleOn(BoardsViewModel.BoardTypes theType)
        {
            if (!BoardsInvisibleTo.Contains(theType))
            {
                return;
            }
            BoardsInvisibleTo.Remove(theType);
        }

        internal void MarkInvisibleOn(BoardsViewModel.BoardTypes theType)
        {
            BoardsInvisibleTo.Add(theType);
        }


        internal bool HasVisualWithID(Guid guid)
        {
            if (TheCharImageFactory != null && TheCharImageFactory.FactoryVisualID == guid)
            {
                return true;
            }
            if (TheInfoTextFactory != null && TheInfoTextFactory.FactoryVisualID == guid)
            {
                return true;
            }
            if (TheBaseConeFactory != null && TheBaseConeFactory.FactoryVisualID == guid)
            {
                return true;
            }
            if (MovementCirclesFactories != null && 
                MovementCirclesFactories.Any(x=>x.FactoryVisualID==guid))
            {
                return true;
            }
            return false;
        }
    }
}